﻿// Inner Kit 库
// 通用工具类
// Copyright (c) 2023 by 尔西大帝. All rights reserved.
//
// 这个文件包括一些常量与宏的定义。以及所有项目都要用到的最基础的工具。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-14

#include "common_utils.h"

#include <codecvt>
#include <cstdarg>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>

namespace ikit {
static FILE* log_stream = nullptr;
static const char* log_filename = nullptr;
static char time_str[256];

// MurmurHash2 64-bit variant
static uint64_t MurmurHash64B(const void* key, int len, unsigned int seed) {
  const unsigned int m = 0x5bd1e995;
  const int r = 24;
  unsigned int h1 = seed ^ len;
  unsigned int h2 = 0;
  const unsigned int* data = (const unsigned int*)key;

  while (len >= 8) {
    unsigned int k1 = *data++;
    k1 *= m;
    k1 ^= k1 >> r;
    k1 *= m;
    h1 *= m;
    h1 ^= k1;
    len -= 4;
    unsigned int k2 = *data++;
    k2 *= m;
    k2 ^= k2 >> r;
    k2 *= m;
    h2 *= m;
    h2 ^= k2;
    len -= 4;
  }

  if (len >= 4) {
    unsigned int k1 = *data++;
    k1 *= m;
    k1 ^= k1 >> r;
    k1 *= m;
    h1 *= m;
    h1 ^= k1;
    len -= 4;
  }

  switch (len) {
  case 3:
    h2 ^= ((unsigned char*)data)[2] << 16;
  case 2:
    h2 ^= ((unsigned char*)data)[1] << 8;
  case 1:
    h2 ^= ((unsigned char*)data)[0];
    h2 *= m;
  };

  h1 ^= h2 >> 18;
  h1 *= m;
  h2 ^= h1 >> 22;
  h2 *= m;
  h1 ^= h2 >> 17;
  h1 *= m;
  h2 ^= h1 >> 19;
  h2 *= m;

  uint64_t h = h1;
  h = (h << 32) | h2;
  return h;
}

// MurmurHash1 32-bit variant
static uint32_t murmurhash1_32(const void* key, size_t len, uint32_t seed) {
  const uint8_t* data = (const uint8_t*)key;
  uint32_t h = seed;

  while (len >= 4) {
    uint32_t k = *(uint32_t*)data;
    k *= 0xcc9e2d51;
    k = (k << 15) | (k >> 17);
    k *= 0x1b873593;

    h ^= k;
    h = (h << 13) | (h >> 19);
    h *= 5;

    data += 4;
    len -= 4;
  }

  // Handle remaining bytes (if any)
  uint32_t k = 0;
  switch (len) {
  case 3:
    k ^= data[2] << 16;
  case 2:
    k ^= data[1] << 8;
  case 1:
    k ^= data[0];
    k *= 0xcc9e2d51;
    k = (k << 15) | (k >> 17);
    k *= 0x1b873593;
    h ^= k;
  }

  // Finalize the hash value
  h ^= len;
  h ^= h >> 16;
  h *= 0x85ebca6b;
  h ^= h >> 13;
  h *= 0xc2b2ae35;
  h ^= h >> 16;

  return h;
}

uint32_t hash(const char* str) {
  if (str == nullptr) {
    return -1;
  }
  return murmurhash1_32(str, strlen(str), 0x12345678);
}

uint64_t hash64(const char* str) {
  if (str == nullptr) {
    return -1;
  }
  return MurmurHash64B(str, strlen(str), 0x12345678);
}

void error(const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  va_end(ap);

  printf("\n");
}

void log(const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  va_end(ap);

  printf("\n");
}

void print(const char* format, ...) {
  va_list ap;
  va_start(ap, format);
  vprintf(format, ap);
  va_end(ap);
}

std::string read_txt_file(const char* filename) {  
  auto str_name = std::string(filename);
  std::ifstream file(str_name); // 创建输入文件流对象
  if (!file.is_open()) {
    throw std::runtime_error("Could not open file: " + str_name);
  }

  std::stringstream buffer; // 创建一个字符串流缓冲区
  buffer << file.rdbuf();   // 将文件内容读入缓冲区

  file.close(); // 关闭文件

  return buffer.str(); // 将缓冲区内容转换为字符串并返回
}

std::string replace_with_CrLf(const std::string& input) {
    std::string result = input;
    std::string::size_type pos = 0;
    while ((pos = result.find("\n", pos)) != std::string::npos) {
        result.replace(pos, 1, "\r\n");
        pos += 2; // 移动到新插入的 "\r\n" 之后，避免替换掉 "\r"
    }
    return result;
}

std::string get_log() {
  if (log_stream == nullptr){
    return std::string();
  }

  // 关闭输出流
  fclose(log_stream);
  // 得到文字
  auto text = read_txt_file(log_filename);
  // 重新打开输出流
  set_log_output_file(log_filename, true);

  // 将行尾进行转化
  return replace_with_CrLf(text);
}

std::string get_current_dir() {
  std::filesystem::path current_path = std::filesystem::current_path();
  return current_path.string();
}

void set_log_output_file(const char* filename, bool is_append) {
  log_filename = filename;
  freopen_s(&log_stream, filename, is_append ? "a" : "w", stdout);
}

bool is_number(const char* s) {
  if (s == NULL) {
    return false;
  }
  int count = 0; // 这个用来记录第一个
  // 这个s[i]真太妙了。原来还能这样！
  for (int i = 0; s[i]; i++) {
    if (s[i] < '0' || s[i] > '9') {
      // 第一位可以是负号
      if (s[i] == '-' && count == 0) {
        continue;
      }
      // 忽略空格
      if (s[i] == ' ') {
        continue;
      }

      return false;
    }

    // 如果是因为空格跳过，这里不会增加。所以，前面可以有空格。
    count++;
    if (count > 32) {
      return false;
    }
  }

  return true;
}

bool is_float(const char* s) {
  if (s == NULL) {
    return false;
  }

  int count = 0; // 这个用来记录第一个
  int floatCount = 0;

  // 这个s[i]真太妙了。原来还能这样！
  for (int i = 0; s[i]; i++) {
    if (s[i] < '0' || s[i] > '9') {
      // 可以是点号，但只能是一个
      if (s[i] == '.') {
        if (floatCount == 0) {
          floatCount++;
          continue;
        } else {
          return false;
        }
      }

      // 第一位可以是负号
      if (s[i] == '-' && count == 0) {
        continue;
      }
      // 忽略空格
      if (s[i] == ' ') {
        continue;
      }

      return false;
    }

    // 如果是因为空格跳过，这里不会增加。所以，前面可以有空格。
    count++;
    if (count > 32) {
      return false;
    }
  }

  return true;
}

bool is_hex(const char* s) {
  if (s == NULL) {
    return false;
  }
  int lower;

  // 这个s[i]真太妙了。原来还能这样！
  for (int i = 0; s[i]; i++) {
    lower = tolower(s[i]);

    bool isNumber = lower >= '0' && lower <= '9';
    bool isHex = lower >= 'a' && lower <= 'f';

    if (!(isNumber || isHex)) {
      return false;
    }
  }

  return true;
}

int hex_to_number(char ch) {
  if (ch >= '0' && ch <= '9') {
    return ch - '0';
  }
  if (ch >= 'A' && ch <= 'Z') {
    return ch - 'A' + 10;
  }
  if (ch >= 'a' && ch <= 'z') {
    return ch - 'a' + 10;
  }
  return 0;
}

// 输入字符串，输出相应的16进制；例如：输入"12AB3d"，输出0x12AB3d
uint32_t hex_to_uint(const char* buf) {
  uint32_t sum = 0;
  uint32_t num = 0;
  char ch = 0;

  for (int i = 0; buf[i]; i++) {
    ch = buf[i];

    // 如果前面有0x，需要跳过
    if (ch == '0' && i == 0) {
      continue;
    }
    if (ch == 'x' && i == 1) {
      continue;
    }

    if (ch >= '0' && ch <= '9') {
      num = ch - '0';
    }

    if (ch >= 'A' && ch <= 'F') {
      num = ch - 'A' + 10;
    }

    if (ch >= 'a' && ch <= 'f') {
      num = ch - 'a' + 10;
    }

    sum = sum * 16 + num; // 16进制表达
  }
  return sum;
}

// 复制一个字符串（会重新分配内存）
char* str_copy(const char* str) {
  // 常规检查，如果是空，则返回空
  if (str == nullptr) {
    return nullptr;
  }

  int len = strlen(str) + 1;
  char* new_str = (char*)malloc(len);
  // 这里的LEN会直接复制最后一个'\0'结束符，所以不用再配置'\0'结束符
  if (new_str != nullptr) {
    memcpy(new_str, str, len);
  }
  return new_str;
}

std::string utf8_to_gbk(const std::string& utf8_str) {
  // 将UTF-8字符串转换为宽字符串
  std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
  std::wstring wide_str = utf8_conv.from_bytes(utf8_str);

  // 将宽字符串转换为GBK编码的字符串
  const char* GBK_LOCALE_NAME = ".936"; // GBK在Windows下的locale名称
  std::wstring_convert<std::codecvt_byname<wchar_t, char, mbstate_t>> gbk_conv(
      new std::codecvt_byname<wchar_t, char, mbstate_t>(GBK_LOCALE_NAME));
  std::string gbk_str = gbk_conv.to_bytes(wide_str);

  return gbk_str;
}
} // namespace ikit